home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / mig / dist.old / user.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-29  |  43.8 KB  |  1,473 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1991,1990 Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation is hereby granted, provided that both the copyright
  8.  * notice and this permission notice appear in all copies of the
  9.  * software, derivative works or modified versions, and any portions
  10.  * thereof, and that both notices appear in supporting documentation.
  11.  * 
  12.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
  13.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15.  * 
  16.  * Carnegie Mellon requests users of this software to return to
  17.  * 
  18.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  19.  *  School of Computer Science
  20.  *  Carnegie Mellon University
  21.  *  Pittsburgh PA 15213-3890
  22.  * 
  23.  * any improvements or extensions that they make and grant Carnegie the
  24.  * rights to redistribute these changes.
  25.  */
  26. /*
  27.  * HISTORY
  28.  * $Log:    user.c,v $
  29.  * Revision 2.8  91/08/28  11:17:34  jsb
  30.  *     Added MIG_SERVER_DIED.
  31.  *     [91/08/21            rpd]
  32.  *     Removed Camelot and TrapRoutine support.
  33.  *     Changed MsgKind to MsgSeqno.
  34.  *     [91/08/12            rpd]
  35.  * 
  36.  * Revision 2.7  91/07/31  18:11:31  dbg
  37.  *     Allow indefinite-length variable arrays.  They may be copied
  38.  *     either in-line or out-of-line, depending on size.
  39.  * 
  40.  *     Copy variable-length C Strings with mig_strncpy, to combine
  41.  *     'strcpy' and 'strlen' operations.
  42.  * 
  43.  *     New method for advancing request message pointer past
  44.  *     variable-length arguments.  We no longer have to know the order
  45.  *     of variable-length arguments and their count arguments.
  46.  * 
  47.  *     Remove redundant assignments (to msgh_simple, msgh_size) in
  48.  *     generated code.
  49.  *     [91/07/17            dbg]
  50.  * 
  51.  * Revision 2.6  91/06/26  14:39:44  rpd
  52.  *     Removed the dummy user initialization function,
  53.  *     which was kept for backwards-compatibility.
  54.  *     [91/06/26            rpd]
  55.  * 
  56.  * Revision 2.5  91/06/25  10:32:22  rpd
  57.  *     Cast request and reply ports to mach_port_t in KernelUser stubs.
  58.  *     [91/05/27            rpd]
  59.  * 
  60.  *     Changed HeaderFileName to UserHeaderFileName.
  61.  *     Changed WriteVarDecl to WriteUserVarDecl.
  62.  *     [91/05/23            rpd]
  63.  * 
  64.  * Revision 2.4  91/02/05  17:56:20  mrt
  65.  *     Changed to new Mach copyright
  66.  *     [91/02/01  17:56:28  mrt]
  67.  * 
  68.  * Revision 2.3  90/06/19  23:01:20  rpd
  69.  *     Added UserFilePrefix support.
  70.  *     [90/06/03            rpd]
  71.  * 
  72.  * Revision 2.2  90/06/02  15:06:03  rpd
  73.  *     Created for new IPC.
  74.  *     [90/03/26  21:14:40  rpd]
  75.  * 
  76.  * 07-Apr-89  Richard Draves (rpd) at Carnegie-Mellon University
  77.  *    Extensive revamping.  Added polymorphic arguments.
  78.  *    Allow multiple variable-sized inline arguments in messages.
  79.  *
  80.  * 21-Feb-89  David Golub (dbg) at Carnegie-Mellon University
  81.  *    Get name for header file from HeaderFileName, since it can
  82.  *    change.
  83.  *
  84.  *  8-Feb-89  David Golub (dbg) at Carnegie-Mellon University
  85.  *    Added WriteUserIndividual to put each user-side routine in its
  86.  *    own file.
  87.  *
  88.  *  8-Jul-88  Mary Thompson (mrt) at Carnegie-Mellon University
  89.  *    Declared routines to be mig_external instead of extern,
  90.  *    where mig_external is conditionally defined in <subsystem>.h.
  91.  *    The Avalon folks want to define mig_external to be static
  92.  *    in their compilations because they inlcude the User.c code in
  93.  *    their programs.
  94.  *
  95.  * 23-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  96.  *    Changed the include of camelot_types.h to cam/camelot_types.h
  97.  *
  98.  * 19-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
  99.  *    Added comments for each routine. Called WriteMsgError
  100.  *    for MIG_ARRAY_TOO_LARGE errors.
  101.  *
  102.  * 19-Jan-88  David Golub (dbg) at Carnegie-Mellon University
  103.  *    Change variable-length inline array declarations to use
  104.  *    maximum size specified to Mig.  Make message variable
  105.  *    length if the last item in the message is variable-length
  106.  *    and inline.  Use argMultiplier field to convert between
  107.  *    argument and IPC element counts.
  108.  *
  109.  * 19-Jan-88  Mary Thompson (mrt) at Carnegie-Mellon University
  110.  *    In WriteInitRoutine changed reference from reply_port; to reply_port++;
  111.  *    for lint code.
  112.  *
  113.  * 17-Jan-88  David Detlefs (dld) at Carnegie-Mellon University
  114.  *    Modified to produce C++ compatible code via #ifdefs.
  115.  *    All changes have to do with argument declarations.
  116.  *
  117.  * 16-Nov-87  David Golub (dbg) at Carnegie-Mellon University
  118.  *    Handle variable-length inline arrays.
  119.  *
  120.  * 22-Oct-87  Mary Thompson (mrt) at Carnegie-Mellon University
  121.  *     Added a reference to rep_port in the InitRoutine
  122.  *    with an ifdef lint conditional.
  123.  *
  124.  * 22-Sep-87  Mary Thompson (mrt) at Carnegie-Mellon University
  125.  *    Fixed check for TransId to be a not equal test
  126.  *    rather than an equal test.
  127.  *
  128.  *  2-Sep-87  Mary Thompson (mrt) at Carnegie-Mellon University
  129.  *    Changed WriteCheckIdentity to check TransId instead
  130.  *    of msgh_id for a returned camelot reply
  131.  *
  132.  * 24-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  133.  *    Added a  LINTLIBRARY  line to keep lint
  134.  *    from complaining about routines that are not used.
  135.  *
  136.  * 21-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  137.  *    Added Flag parameter to WritePackMsgType.
  138.  *
  139.  * 12-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  140.  *    Made various camelot changes: include of camelot_types.h
  141.  *    Check for death_pill before correct msg-id.
  142.  *
  143.  * 10-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  144.  *    Renamed get_reply_port and dealloc_reply_port to
  145.  *    mig_get_reply_port and mig_dealloc_reply_port.
  146.  *    Fixed WriteRequestHead to handle MsgType parameter.
  147.  *
  148.  *  3-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
  149.  *    Fixed to generate code that is the same for multi-threaded and
  150.  *    single threaded use. Gets reply port from library routine
  151.  *    get_reply_port and deallocates with routine
  152.  *    dealloc_reply_port. Removed all routines in mig interface code
  153.  *    to keep track of the reply port. The init routine still exists
  154.  *    but does nothing.
  155.  * 
  156.  * 29-Jul_87  Mary Thompson (mrt) at Carnegie-Mellon University
  157.  *     Fixed call to WriteVarDecl to use correspond to
  158.  *    the changes that were made in that routine.
  159.  *
  160.  * 16-Jul-87  Robert Sansom (rds) at Carnegie Mellon University
  161.  *    Added write of MsgType to WriteSetMsgTypeRoutine.
  162.  *
  163.  *  8-Jun-87  Mary Thompson (mrt) at Carnegie-Mellon University
  164.  *    Removed #include of sys/types.h from WriteIncludes.
  165.  *    Changed the KERNEL include from ../h to sys/
  166.  *    Removed extern from WriteUser to make hi-c happy
  167.  *
  168.  * 28-May-87  Richard Draves (rpd) at Carnegie-Mellon University
  169.  *    Created.
  170.  */
  171.  
  172. #include <assert.h>
  173.  
  174. #include <mach/message.h>
  175. #include "write.h"
  176. #include "error.h"
  177. #include "utils.h"
  178. #include "global.h"
  179.  
  180. /*************************************************************
  181.  *    Writes the standard includes. The subsystem specific
  182.  *    includes  are in <SubsystemName>.h and writen by
  183.  *    header:WriteHeader. Called by WriteProlog.
  184.  *************************************************************/
  185. static void
  186. WriteIncludes(file)
  187.     FILE *file;
  188. {
  189.     if (IsKernelServer)
  190.     {
  191.     /*
  192.      *    We want to get the user-side definitions of types
  193.      *    like task_t, ipc_space_t, etc. in mach/mach_types.h.
  194.      */
  195.  
  196.     fprintf(file, "#undef\tKERNEL\n");
  197.  
  198.     if (InternalHeaderFileName != strNULL)
  199.     {
  200.         register char *cp;
  201.  
  202.         /* Strip any leading path from InternalHeaderFileName. */
  203.         cp = rindex(InternalHeaderFileName, '/');
  204.         if (cp == 0)
  205.         cp = InternalHeaderFileName;
  206.         else
  207.         cp++;    /* skip '/' */
  208.         fprintf(file, "#include \"%s\"\n", cp);
  209.     }
  210.     }
  211.  
  212.     if (UserHeaderFileName != strNULL)
  213.     {
  214.     register char *cp;
  215.  
  216.     /* Strip any leading path from UserHeaderFileName. */
  217.     cp = rindex(UserHeaderFileName, '/');
  218.     if (cp == 0)
  219.         cp = UserHeaderFileName;
  220.     else
  221.         cp++;    /* skip '/' */
  222.     fprintf(file, "#include \"%s\"\n", cp);
  223.     }
  224.  
  225.     fprintf(file, "#define EXPORT_BOOLEAN\n");
  226.     fprintf(file, "#include <mach/boolean.h>\n");
  227.     fprintf(file, "#include <mach/kern_return.h>\n");
  228.     fprintf(file, "#include <mach/message.h>\n");
  229.     fprintf(file, "#include <mach/notify.h>\n");
  230.     fprintf(file, "#include <mach/mach_types.h>\n");
  231.     fprintf(file, "#include <mach/mig_errors.h>\n");
  232.     fprintf(file, "#include <mach/msg_type.h>\n");
  233.     if (!IsKernelServer)
  234.     {
  235.     /* note KERNEL is undefined when IsKernelServer */
  236.     fprintf(file, "#ifndef\tKERNEL\n");
  237.     fprintf(file, "#include <strings.h>\n");
  238.     fprintf(file, "#endif\tKERNEL\n");
  239.     }
  240.     fprintf(file, "/* LINTLIBRARY */\n");
  241.     fprintf(file, "\n");
  242.     fprintf(file, "extern mach_port_t mig_get_reply_port();\n");
  243.     fprintf(file, "extern void mig_dealloc_reply_port();\n");
  244.     fprintf(file, "\n");
  245. }
  246.  
  247. static void
  248. WriteGlobalDecls(file)
  249.     FILE *file;
  250. {
  251.     if (RCSId != strNULL)
  252.     WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId);
  253.  
  254.     fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
  255.     fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
  256.     fprintf(file, "\n");
  257. }
  258.  
  259. /*************************************************************
  260.  *    Writes the standard #includes, #defines, and
  261.  *    RCS declaration. Called by WriteUser.
  262.  *************************************************************/
  263. static void
  264. WriteProlog(file)
  265.     FILE *file;
  266. {
  267.     WriteIncludes(file);
  268.     WriteBogusDefines(file);
  269.     WriteGlobalDecls(file);
  270. }
  271.  
  272. /*ARGSUSED*/
  273. static void
  274. WriteEpilog(file)
  275.     FILE *file;
  276. {
  277. }
  278.  
  279. static string_t
  280. WriteHeaderPortType(arg)
  281.     argument_t *arg;
  282. {
  283.     if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC)
  284.     return arg->argPoly->argVarName;
  285.     else
  286.     return arg->argType->itInNameStr;
  287. }
  288.  
  289. static void
  290. WriteRequestHead(file, rt)
  291.     FILE *file;
  292.     routine_t *rt;
  293. {
  294.     if (rt->rtMaxRequestPos > 0)
  295.     fprintf(file, "\tInP = &Mess.In;\n");
  296.  
  297.     if (rt->rtSimpleFixedRequest) {
  298.     fprintf(file, "\tInP->Head.msgh_bits =");
  299.     if (!rt->rtSimpleSendRequest)
  300.         fprintf(file, " MACH_MSGH_BITS_COMPLEX|");
  301.     fprintf(file, "\n");
  302.     fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n",
  303.         WriteHeaderPortType(rt->rtRequestPort),
  304.         WriteHeaderPortType(rt->rtReplyPort));
  305.     } else {
  306.     fprintf(file, "\tInP->Head.msgh_bits = msgh_simple ?\n");
  307.     fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s) :\n",
  308.         WriteHeaderPortType(rt->rtRequestPort),
  309.         WriteHeaderPortType(rt->rtReplyPort));
  310.     fprintf(file, "\t\t(MACH_MSGH_BITS_COMPLEX|\n");
  311.     fprintf(file, "\t\t MACH_MSGH_BITS(%s, %s));\n",
  312.         WriteHeaderPortType(rt->rtRequestPort),
  313.         WriteHeaderPortType(rt->rtReplyPort));
  314.     }
  315.  
  316.     fprintf(file, "\t/* msgh_size passed as argument */\n");
  317.  
  318.     /*
  319.      *    KernelUser stubs need to cast the request and reply ports
  320.      *    from ipc_port_t to mach_port_t.
  321.      */
  322.  
  323.     if (IsKernelUser)
  324.     fprintf(file, "\tInP->%s = (mach_port_t) %s;\n",
  325.         rt->rtRequestPort->argMsgField,
  326.         rt->rtRequestPort->argVarName);
  327.     else
  328.     fprintf(file, "\tInP->%s = %s;\n",
  329.         rt->rtRequestPort->argMsgField,
  330.         rt->rtRequestPort->argVarName);
  331.  
  332.     if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) {
  333.     if (IsKernelUser)
  334.         fprintf(file, "\tInP->%s = (mach_port_t) %s;\n",
  335.             rt->rtReplyPort->argMsgField,
  336.             rt->rtReplyPort->argVarName);
  337.     else
  338.         fprintf(file, "\tInP->%s = %s;\n",
  339.             rt->rtReplyPort->argMsgField,
  340.             rt->rtReplyPort->argVarName);
  341.     } else if (rt->rtOneWay || IsKernelUser)
  342.     fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n",
  343.         rt->rtReplyPort->argMsgField);
  344.     else
  345.     fprintf(file, "\tInP->%s = mig_get_reply_port();\n",
  346.         rt->rtReplyPort->argMsgField);
  347.  
  348.     fprintf(file, "\tInP->Head.msgh_seqno = 0;\n");
  349.     fprintf(file, "\tInP->Head.msgh_id = %d;\n",
  350.         rt->rtNumber + SubsystemBase);
  351. }
  352.  
  353. /*************************************************************
  354.  *  Writes declarations for the message types, variables
  355.  *  and return  variable if needed. Called by WriteRoutine.
  356.  *************************************************************/
  357. static void
  358. WriteVarDecls(file, rt)
  359.     FILE *file;
  360.     routine_t *rt;
  361. {
  362.     fprintf(file, "\tunion {\n");
  363.     fprintf(file, "\t\tRequest In;\n");
  364.     if (!rt->rtOneWay)
  365.     fprintf(file, "\t\tReply Out;\n");
  366.     fprintf(file, "\t} Mess;\n");
  367.     fprintf(file, "\n");
  368.  
  369.     fprintf(file, "\tregister Request *InP = &Mess.In;\n");
  370.     if (!rt->rtOneWay)
  371.     fprintf(file, "\tregister Reply *OutP = &Mess.Out;\n");
  372.     fprintf(file, "\n");
  373.  
  374.     if (!rt->rtOneWay || rt->rtProcedure)
  375.     fprintf(file, "\tmach_msg_return_t msg_result;\n");
  376.  
  377.     if (!rt->rtSimpleFixedRequest)
  378.     fprintf(file, "\tboolean_t msgh_simple = %s;\n",
  379.         strbool(rt->rtSimpleSendRequest));
  380.     else if (!rt->rtOneWay &&
  381.          !(rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)) {
  382.     fprintf(file, "#if\tTypeCheck\n");
  383.     fprintf(file, "\tboolean_t msgh_simple;\n");
  384.     fprintf(file, "#endif\tTypeCheck\n");
  385.     }
  386.  
  387.     if (rt->rtNumRequestVar > 0)
  388.     fprintf(file, "\tunsigned int msgh_size;\n");
  389.     else if (!rt->rtOneWay && !rt->rtNoReplyArgs)
  390.     {
  391.     fprintf(file, "#if\tTypeCheck\n");
  392.     fprintf(file, "\tunsigned int msgh_size;\n");
  393.     fprintf(file, "#endif\tTypeCheck\n");
  394.     }
  395.  
  396.     /* if either request or reply is variable, we need msgh_size_delta */
  397.     if ((rt->rtMaxRequestPos > 0) ||
  398.     (rt->rtMaxReplyPos > 0))
  399.     fprintf(file, "\tunsigned int msgh_size_delta;\n");
  400.  
  401.     fprintf(file, "\n");
  402. }
  403.  
  404. /*************************************************************
  405.  *  Writes code to call the user provided error procedure
  406.  *  when a MIG error occurs. Called by WriteMsgSend, 
  407.  *  WriteMsgCheckReceive, WriteMsgSendReceive, WriteCheckIdentity,
  408.  *  WriteRetCodeCheck, WriteTypeCheck, WritePackArgValue.
  409.  *************************************************************/
  410. static void
  411. WriteMsgError(file, rt, error)
  412.     FILE *file;
  413.     routine_t *rt;
  414.     char *error;
  415. {
  416.     if (rt->rtProcedure)
  417.     fprintf(file, "\t\t{ %s(%s); return; }\n", rt->rtErrorName, error);
  418.     else if (rt->rtReturn != rt->rtRetCode)
  419.     {
  420.     fprintf(file, "\t\t{ %s(%s); ", rt->rtErrorName, error);
  421.     if (rt->rtNumReplyVar > 0)
  422.         fprintf(file, "OutP = &Mess.Out; ");
  423.     fprintf(file, "return OutP->%s; }\n", rt->rtReturn->argMsgField);
  424.     }
  425.     else
  426.     fprintf(file, "\t\treturn %s;\n", error);
  427. }
  428.  
  429. /*************************************************************
  430.  *   Writes the send call when there is to be no subsequent
  431.  *   receive. Called by WriteRoutine for SimpleProcedures
  432.  *   or SimpleRoutines
  433.  *************************************************************/
  434. static void
  435. WriteMsgSend(file, rt)
  436.     FILE *file;
  437.     routine_t *rt;
  438. {
  439.     char *SendSize = (rt->rtNumRequestVar == 0)
  440.             ? "sizeof(Request)"
  441.             : "msgh_size";
  442.  
  443.     char *MsgResult = (rt->rtProcedure)
  444.             ? "msg_result ="
  445.             : "return";
  446.  
  447.     if (IsKernelUser)
  448.     {
  449.     fprintf(file, "\t%s mach_msg_send_from_kernel(", MsgResult);
  450.     fprintf(file, "&InP->Head, %s);\n", SendSize);
  451.     }
  452.     else
  453.     {
  454.     fprintf(file, "\t%s mach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0,",
  455.         MsgResult,
  456.         rt->rtMsgOption->argVarName,
  457.         SendSize);
  458.     fprintf(file,
  459.         " MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n"
  460.         );
  461.     }
  462.  
  463.     if (rt->rtProcedure)
  464.     {
  465.     fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
  466.     WriteMsgError(file, rt, "msg_result");
  467.     }
  468. }
  469.  
  470. /*************************************************************
  471.  *  Writes to code to check for error returns from receive.
  472.  *  Called by WriteMsgSendReceive and WriteMsgRPC
  473.  *************************************************************/
  474. static void
  475. WriteMsgCheckReceive(file, rt, success)
  476.     FILE *file;
  477.     routine_t *rt;
  478.     char *success;
  479. {
  480.     fprintf(file, "\tif (msg_result != %s) {\n", success);
  481.     if (!akCheck(rt->rtReplyPort->argKind, akbUserArg) && !IsKernelUser)
  482.     {
  483.     /* If we aren't using a user-supplied reply port, then
  484.        deallocate the reply port when it is invalid or
  485.        for TIMED_OUT errors. */
  486.  
  487.     fprintf(file, "\t\tif ((msg_result == MACH_SEND_INVALID_REPLY) ||\n");
  488.     if (rt->rtWaitTime != argNULL)
  489.         fprintf(file, "\t\t    (msg_result == MACH_RCV_TIMED_OUT) ||\n");
  490.     fprintf(file, "\t\t    (msg_result == MACH_RCV_INVALID_NAME))\n");
  491.     fprintf(file, "\t\t\tmig_dealloc_reply_port();\n");
  492.     }
  493.     WriteMsgError(file, rt, "msg_result");
  494.     fprintf(file, "\t}\n");
  495. }
  496.  
  497. /*************************************************************
  498.  *  Writes the send and receive calls and code to check
  499.  *  for errors. Normally the rpc code is generated instead
  500.  *  although, the subsytem can be compiled with the -R option
  501.  *  which will cause this code to be generated. Called by
  502.  *  WriteRoutine if UseMsgRPC option is false.
  503.  *************************************************************/
  504. static void
  505. WriteMsgSendReceive(file, rt)
  506.     FILE *file;
  507.     routine_t *rt;
  508. {
  509.     char *SendSize = (rt->rtNumRequestVar == 0)
  510.             ? "sizeof(Request)"
  511.             : "msgh_size";
  512.  
  513.     fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n",
  514.         rt->rtMsgOption->argVarName,
  515.         SendSize);
  516.  
  517.     fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
  518.     WriteMsgError(file, rt, "msg_result");
  519.     fprintf(file, "\n");
  520.  
  521.     fprintf(file, "\tmsg_result = mach_msg(&OutP->Head, MACH_RCV_MSG|%s%s, 0, sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n",
  522.         rt->rtMsgOption->argVarName,
  523.         rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
  524.         rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
  525.     WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
  526.     fprintf(file, "\n");
  527. }
  528.  
  529. static void
  530. WriteMsgReceive(file, rt)
  531.     FILE *file;
  532.     routine_t *rt;
  533. {
  534.     fprintf(file, "\tmsg_result = mach_msg(&OutP->Head, MACH_RCV_MSG|%s%s, 0, sizeof(Reply), %s, %s, MACH_PORT_NULL);\n",
  535.         rt->rtMsgOption->argVarName,
  536.         rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
  537.         rt->rtReplyPort->argVarName,
  538.         rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
  539.     WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
  540.     fprintf(file, "\n");
  541. }
  542.  
  543. /*************************************************************
  544.  *  Writes the rpc call and the code to check for errors.
  545.  *  This is the default code to be generated. Called by WriteRoutine
  546.  *  for all routine types except SimpleProcedure and SimpleRoutine.
  547.  *************************************************************/
  548. static void
  549. WriteMsgRPC(file, rt)
  550.     FILE *file;
  551.     routine_t *rt;
  552. {
  553.     char *SendSize = (rt->rtNumRequestVar == 0)
  554.             ? "sizeof(Request)"
  555.             : "msgh_size";
  556.  
  557.     if (IsKernelUser)
  558.     fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, sizeof(Reply));\n", SendSize);
  559.     else
  560.     fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s, %s, sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n",
  561.         rt->rtMsgOption->argVarName,
  562.         rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
  563.         SendSize,
  564.         rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
  565.     WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
  566.     fprintf(file, "\n");
  567. }
  568.  
  569. /*************************************************************
  570.  *   Sets the correct value of the dealloc flag and calls
  571.  *   Utils:WritePackMsgType to fill in the ipc msg type word(s)
  572.  *   in the request message. Called by WriteRoutine for each
  573.  *   argument that is to be sent in the request message.
  574.  *************************************************************/
  575. static void
  576. WritePackArgType(file, arg)
  577.     FILE *file;
  578.     argument_t *arg;
  579. {
  580.     WritePackMsgType(file, arg->argType, arg->argDeallocate, arg->argLongForm,
  581.              TRUE, "InP->%s", "%s", arg->argTTName);
  582.     fprintf(file, "\n");
  583. }
  584.  
  585. /*************************************************************
  586.  *  Writes code to copy an argument into the request message.  
  587.  *  Called by WriteRoutine for each argument that is to placed
  588.  *  in the request message.
  589.  *************************************************************/
  590. static void
  591. WritePackArgValue(file, arg)
  592.     FILE *file;
  593.     register argument_t *arg;
  594. {
  595.     register ipc_type_t *it = arg->argType;
  596.     register char *ref = argByReferenceUser(arg) ? "*" : "";
  597.  
  598.     if (it->itInLine && it->itVarArray) {
  599.  
  600.     if (it->itString) {
  601.         /*
  602.          *    Copy variable-size C string with mig_strncpy.
  603.          *    Save the string length (+ 1 for trailing 0)
  604.          *    in the argument`s count field.
  605.          */
  606.         fprintf(file,
  607.         "\tInP->%s = mig_strncpy(InP->%s, %s, %d);\n",
  608.         arg->argCount->argMsgField,
  609.         arg->argMsgField,
  610.         arg->argVarName,
  611.         it->itNumber);
  612.     }
  613.     else {
  614.  
  615.         /*
  616.          *    Copy in variable-size inline array with bcopy,
  617.          *    after checking that number of elements doesn`t
  618.          *    exceed declared maximum.
  619.          */
  620.         register argument_t *count = arg->argCount;
  621.         register char *countRef = argByReferenceUser(count) ? "*" : "";
  622.         register ipc_type_t *btype = it->itElement;
  623.  
  624.         /* Note btype->itNumber == count->argMultiplier */
  625.  
  626.         fprintf(file, "\tif (%s%s > %d) {\n",
  627.         countRef, count->argVarName,
  628.         it->itNumber/btype->itNumber);
  629.         if (it->itIndefinite) {
  630.         fprintf(file, "\t\tInP->%s.msgtl_header.msgt_inline = FALSE;\n",
  631.             arg->argTTName);
  632.         fprintf(file, "\t\t*((%s **)InP->%s) = %s%s;\n",
  633.             FetchUserType(btype),
  634.             arg->argMsgField,
  635.             ref, arg->argVarName);
  636.         if (!arg->argRoutine->rtSimpleFixedRequest)
  637.             fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  638.         }
  639.         else
  640.         WriteMsgError(file, arg->argRoutine, "MIG_ARRAY_TOO_LARGE");
  641.  
  642.         fprintf(file, "\t}\n\telse {\n");
  643.  
  644.         fprintf(file, "\t\tbcopy((char *) %s%s, (char *) InP->%s, ",
  645.         ref, arg->argVarName, arg->argMsgField);
  646.         if (btype->itTypeSize > 1)
  647.         fprintf(file, "%d * ", btype->itTypeSize);
  648.         fprintf(file, "%s%s);\n",
  649.         countRef, count->argVarName);
  650.         fprintf(file, "\t}\n");
  651.     }
  652.     }
  653.     else if (arg->argMultiplier > 1)
  654.     WriteCopyType(file, it, "InP->%s", "/* %s */ %d * %s%s",
  655.               arg->argMsgField, arg->argMultiplier,
  656.               ref, arg->argVarName);
  657.     else
  658.     WriteCopyType(file, it, "InP->%s", "/* %s */ %s%s",
  659.               arg->argMsgField, ref, arg->argVarName);
  660.     fprintf(file, "\n");
  661. }
  662.  
  663. static void
  664. WriteAdjustMsgSimple(file, arg)
  665.     FILE *file;
  666.     register argument_t *arg;
  667. {
  668.     if (!arg->argRoutine->rtSimpleFixedRequest)
  669.     {
  670.     register char *ref = argByReferenceUser(arg) ? "*" : "";
  671.  
  672.     fprintf(file, "\tif (MACH_MSG_TYPE_PORT_ANY(%s%s))\n",
  673.         ref, arg->argVarName);
  674.     fprintf(file, "\t\tmsgh_simple = FALSE;\n");
  675.     fprintf(file, "\n");
  676.     }
  677. }
  678.  
  679. /*
  680.  * Calculate the size of a variable-length message field.
  681.  */
  682. static void
  683. WriteArgSize(file, arg)
  684.     FILE *file;
  685.     register argument_t *arg;
  686. {
  687.     register ipc_type_t *ptype = arg->argType;
  688.     register int bsize = ptype->itElement->itTypeSize;
  689.     register argument_t *count = arg->argCount;
  690.  
  691.     if (ptype->itIndefinite) {
  692.     /*
  693.      *    Check descriptor.  If out-of-line, use standard size.
  694.      */
  695.     fprintf(file, "(InP->%s.msgtl_header.msgt_inline) ? ",
  696.         arg->argTTName);
  697.     }
  698.     if (bsize > 1)
  699.     fprintf(file, "%d * ", bsize);
  700.     if (ptype->itString)
  701.     /* get count from descriptor in message */
  702.     fprintf(file, "InP->%s", count->argMsgField);
  703.     else
  704.     /* get count from argument */
  705.     fprintf(file, "%s%s",
  706.         argByReferenceUser(count) ? "*" : "",
  707.         count->argVarName);
  708.  
  709.     /*
  710.      * If the base type size is not a multiple of sizeof(int) [4],
  711.      * we have to round up.
  712.      */
  713.     if (bsize % 4 != 0)
  714.     fprintf(file, " + 3 & ~3");
  715.  
  716.     if (ptype->itIndefinite) {
  717.     fprintf(file, " : sizeof(%s *)",
  718.         FetchUserType(ptype->itElement));
  719.     }
  720. }
  721.  
  722. /*
  723.  * Adjust message size and advance request pointer.
  724.  * Called after packing a variable-length argument that
  725.  * has more arguments following.
  726.  */
  727. static void
  728. WriteAdjustMsgSize(file, arg)
  729.     FILE *file;
  730.     register argument_t *arg;
  731. {
  732.     register ipc_type_t *ptype = arg->argType;
  733.  
  734.     /* There are more In arguments.  We need to adjust msgh_size
  735.        and advance InP, so we save the size of the current field
  736.        in msgh_size_delta. */
  737.  
  738.     fprintf(file, "\tmsgh_size_delta = ");
  739.     WriteArgSize(file, arg);
  740.     fprintf(file, ";\n");
  741.  
  742.     if (arg->argRequestPos == 0)
  743.     /* First variable-length argument.  The previous msgh_size value
  744.        is the minimum request size. */
  745.  
  746.     fprintf(file, "\tmsgh_size = %d + msgh_size_delta;\n",
  747.         arg->argRoutine->rtRequestSize);
  748.     else
  749.     fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
  750.  
  751.     fprintf(file,
  752.     "\tInP = (Request *) ((char *) InP + msgh_size_delta - %d);\n",
  753.     ptype->itTypeSize + ptype->itPadSize);
  754. }
  755.  
  756. /*
  757.  * Calculate the size of the message.  Called after the
  758.  * last argument has been packed.
  759.  */
  760. static void
  761. WriteFinishMsgSize(file, arg)
  762.     FILE *file;
  763.     register argument_t *arg;
  764. {
  765.     /* No more In arguments.  If this is the only variable In
  766.        argument, the previous msgh_size value is the minimum
  767.        request size. */
  768.  
  769.     if (arg->argRequestPos == 0) {
  770.     fprintf(file, "\tmsgh_size = %d + (",
  771.             arg->argRoutine->rtRequestSize);
  772.     WriteArgSize(file, arg);
  773.     fprintf(file, ");\n");
  774.     }
  775.     else {
  776.         fprintf(file, "\tmsgh_size += ");
  777.     WriteArgSize(file, arg);
  778.         fprintf(file, ";\n");
  779.     }
  780. }
  781.  
  782. /*
  783.  * Called for every argument.  Responsible for packing that
  784.  * argument into the request message.
  785.  */
  786. static void
  787. WritePackArg(file, arg)
  788.     FILE *file;
  789.     register argument_t *arg;
  790. {
  791.     if (akCheck(arg->argKind, akbRequest))
  792.     WritePackArgType(file, arg);
  793.  
  794.     if ((akIdent(arg->argKind) == akePoly) &&
  795.     akCheck(arg->argKind, akbSendSnd))
  796.     WriteAdjustMsgSimple(file, arg);
  797.  
  798.     if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody))
  799.     WritePackArgValue(file, arg);
  800. }
  801.  
  802. /*
  803.  * Generate code to fill in all of the request arguments and their
  804.  * message types.
  805.  */
  806. WriteRequestArgs(file, rt)
  807.     FILE *file;
  808.     register routine_t *rt;
  809. {
  810.     register argument_t *arg;
  811.     register argument_t *lastVarArg;
  812.  
  813.     lastVarArg = argNULL;
  814.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  815.  
  816.     /*
  817.      * Adjust message size and advance message pointer if
  818.      * the last request argument was variable-length and the
  819.      * request position will change.
  820.      */
  821.     if (lastVarArg != argNULL &&
  822.         lastVarArg->argRequestPos < arg->argRequestPos)
  823.     {
  824.         WriteAdjustMsgSize(file, lastVarArg);
  825.         lastVarArg = argNULL;
  826.     }
  827.  
  828.     /*
  829.      * Copy the argument
  830.      */
  831.     WritePackArg(file, arg);
  832.  
  833.     /*
  834.      * Remember whether this was variable-length.
  835.      */
  836.     if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable))
  837.         lastVarArg = arg;
  838.     }
  839.  
  840.     /*
  841.      * Finish the message size.
  842.      */
  843.     if (lastVarArg != argNULL)
  844.     WriteFinishMsgSize(file, lastVarArg);
  845. }
  846.  
  847. /*************************************************************
  848.  *  Writes code to check that the return msgh_id is correct and that
  849.  *  the size of the return message is correct. Called by
  850.  *  WriteRoutine.
  851.  *************************************************************/
  852. static void
  853. WriteCheckIdentity(file, rt)
  854.     FILE *file;
  855.     routine_t *rt;
  856. {
  857.     fprintf(file, "\tif (OutP->Head.msgh_id != %d) {\n",
  858.         rt->rtNumber + SubsystemBase + 100);
  859.     fprintf(file, "\t\tif (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n");
  860.     WriteMsgError(file, rt, "MIG_SERVER_DIED");
  861.     fprintf(file, "\t\telse\n");
  862.     WriteMsgError(file, rt, "MIG_REPLY_MISMATCH");
  863.     fprintf(file, "\t}\n");
  864.     fprintf(file, "\n");
  865.     fprintf(file, "#if\tTypeCheck\n");
  866.  
  867.     if (rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)
  868.     {
  869.     /* Expecting a simple message.  We can factor out the check for
  870.        a simple message, since the error reply message is also simple.
  871.        */
  872.  
  873.     if (!rt->rtNoReplyArgs)
  874.         fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n\n");
  875.  
  876.     fprintf(file,
  877.         "\tif ((OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
  878.     if (rt->rtNoReplyArgs)
  879.         fprintf(file, "\t    (OutP->Head.msgh_size != %d))\n",
  880.             rt->rtReplySize);
  881.     else {
  882.         fprintf(file, "\t    ((msgh_size %s %d) &&\n",
  883.         (rt->rtNumReplyVar > 0) ? "<" : "!=",
  884.         rt->rtReplySize);
  885.         fprintf(file, "\t     ((msgh_size != sizeof(mig_reply_header_t)) ||\n");
  886.         fprintf(file, "\t      (OutP->RetCode == KERN_SUCCESS))))\n");
  887.     }
  888.     }
  889.     else {
  890.     /* Expecting a complex message, or may vary at run time. */
  891.  
  892.     fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n");
  893.     fprintf(file, "\tmsgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
  894.     fprintf(file, "\n");
  895.  
  896.     fprintf(file, "\tif (((msgh_size %s %d)",
  897.         (rt->rtNumReplyVar > 0) ? "<" : "!=",
  898.         rt->rtReplySize);
  899.  
  900.     if (rt->rtSimpleCheckReply)
  901.         /* if rtSimpleReceiveReply was true, then we would have
  902.            executed the code above.  So we know that the message
  903.            is complex. */
  904.         fprintf(file, " || msgh_simple");
  905.     fprintf(file, ") &&\n");
  906.  
  907.     fprintf(file, "\t    ((msgh_size != sizeof(mig_reply_header_t)) ||\n");
  908.     fprintf(file, "\t     !msgh_simple ||\n");
  909.     fprintf(file, "\t     (OutP->RetCode == KERN_SUCCESS)))\n");
  910.     }
  911.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  912.     fprintf(file, "#endif\tTypeCheck\n");
  913.     fprintf(file, "\n");
  914. }
  915.  
  916. /*************************************************************
  917.  *  Write code to generate error handling code if the RetCode
  918.  *  argument of a Routine is not KERN_SUCCESS.
  919.  *************************************************************/
  920. static void
  921. WriteRetCodeCheck(file, rt)
  922.     FILE *file;
  923.     routine_t *rt;
  924. {
  925.     fprintf(file, "\tif (OutP->RetCode != KERN_SUCCESS)\n");
  926.     WriteMsgError(file, rt, "OutP->RetCode");
  927.     fprintf(file, "\n");
  928. }
  929.  
  930. /*************************************************************
  931.  *  Writes code to check that the type of each of the arguments
  932.  *  in the reply message is what is expected. Called by 
  933.  *  WriteRoutine for each argument in the reply message.
  934.  *************************************************************/
  935. static void
  936. WriteTypeCheck(file, arg)
  937.     FILE *file;
  938.     register argument_t *arg;
  939. {
  940.     register ipc_type_t *it = arg->argType;
  941.     register routine_t *rt = arg->argRoutine;
  942.  
  943.     fprintf(file, "#if\tTypeCheck\n");
  944.     if (akCheck(arg->argKind, akbReplyQC))
  945.     {
  946.     fprintf(file, "#if\tUseStaticMsgType\n");
  947.     fprintf(file, "\tif (* (int *) &OutP->%s != * (int *) &%sCheck)\n",
  948.         arg->argTTName, arg->argVarName);
  949.     fprintf(file, "#else\tUseStaticMsgType\n");
  950.     }
  951.     fprintf(file, "\tif (");
  952.     if (!it->itIndefinite) {
  953.     fprintf(file, "(OutP->%s%s.msgt_inline != %s) ||\n\t    ",
  954.         arg->argTTName,
  955.         arg->argLongForm ? ".msgtl_header" : "",
  956.         strbool(it->itInLine));
  957.     }
  958.     fprintf(file, "(OutP->%s%s.msgt_longform != %s) ||\n",
  959.         arg->argTTName,
  960.         arg->argLongForm ? ".msgtl_header" : "",
  961.         strbool(arg->argLongForm));
  962.     if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
  963.     {
  964.     if (!rt->rtSimpleCheckReply)
  965.         fprintf(file, "\t    (MACH_MSG_TYPE_PORT_ANY(OutP->%s.msgt%s_name) && msgh_simple) ||\n",
  966.             arg->argTTName,
  967.             arg->argLongForm ? "l" : "");
  968.     }
  969.     else
  970.     fprintf(file, "\t    (OutP->%s.msgt%s_name != %s) ||\n",
  971.         arg->argTTName,
  972.         arg->argLongForm ? "l" : "",
  973.         it->itOutNameStr);
  974.     if (!it->itVarArray)
  975.     fprintf(file, "\t    (OutP->%s.msgt%s_number != %d) ||\n",
  976.         arg->argTTName,
  977.         arg->argLongForm ? "l" : "",
  978.         it->itNumber);
  979.     fprintf(file, "\t    (OutP->%s.msgt%s_size != %d))\n",
  980.         arg->argTTName,
  981.         arg->argLongForm ? "l" : "",
  982.         it->itSize);
  983.     if (akCheck(arg->argKind, akbReplyQC))
  984.     fprintf(file, "#endif\tUseStaticMsgType\n");
  985.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  986.     fprintf(file, "#endif\tTypeCheck\n");
  987.     fprintf(file, "\n");
  988. }
  989.  
  990. static void
  991. WriteCheckArgSize(file, arg)
  992.     FILE *file;
  993.     register argument_t *arg;
  994. {
  995.     register ipc_type_t *ptype = arg->argType;
  996.     register ipc_type_t *btype = ptype->itElement;
  997.     argument_t *count = arg->argCount;
  998.     int multiplier = btype->itTypeSize / btype->itNumber;
  999.  
  1000.     if (ptype->itIndefinite) {
  1001.     /*
  1002.      * Check descriptor.  If out-of-line, use standard size.
  1003.      */
  1004.     fprintf(file, "(OutP->%s.msgtl_header.msgt_inline) ? ",
  1005.         arg->argTTName);
  1006.     }
  1007.  
  1008.     if (multiplier > 1)
  1009.     fprintf(file, "%d * ", multiplier);
  1010.  
  1011.     fprintf(file, "OutP->%s", count->argMsgField);
  1012.  
  1013.     /* If the base type size of the data field isn`t a multiple of 4,
  1014.        we have to round up. */
  1015.     if (btype->itTypeSize % 4 != 0)
  1016.     fprintf(file, " + 3 & ~3");
  1017.  
  1018.     if (ptype->itIndefinite)
  1019.     fprintf(file, " : sizeof(%s *)", FetchUserType(btype));
  1020. }
  1021.  
  1022. static void
  1023. WriteCheckMsgSize(file, arg)
  1024.     FILE *file;
  1025.     register argument_t *arg;
  1026. {
  1027.     register routine_t *rt = arg->argRoutine;
  1028.  
  1029.     /* If there aren't any more Out args after this, then
  1030.        we can use the msgh_size_delta value directly in
  1031.        the TypeCheck conditional. */
  1032.  
  1033.     if (arg->argReplyPos == rt->rtMaxReplyPos)
  1034.     {
  1035.     fprintf(file, "#if\tTypeCheck\n");
  1036.     fprintf(file, "\tif (msgh_size != %d + (",
  1037.         rt->rtReplySize);
  1038.     WriteCheckArgSize(file, arg);
  1039.     fprintf(file, "))\n");
  1040.  
  1041.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  1042.     fprintf(file, "#endif\tTypeCheck\n");
  1043.     }
  1044.     else
  1045.     {
  1046.     /* If there aren't any more variable-sized arguments after this,
  1047.        then we must check for exact msg-size and we don't need
  1048.        to update msgh_size. */
  1049.  
  1050.     boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar;
  1051.  
  1052.     /* calculate the actual size in bytes of the data field.  note
  1053.        that this quantity must be a multiple of four.  hence, if
  1054.        the base type size isn't a multiple of four, we have to
  1055.        round up.  note also that btype->itNumber must
  1056.        divide btype->itTypeSize (see itCalculateSizeInfo). */
  1057.  
  1058.     fprintf(file, "\tmsgh_size_delta = ");
  1059.     WriteCheckArgSize(file, arg);
  1060.     fprintf(file, ";\n");
  1061.     fprintf(file, "#if\tTypeCheck\n");
  1062.  
  1063.     /* Don't decrement msgh_size until we've checked that
  1064.        it won't underflow. */
  1065.  
  1066.     if (LastVarArg)
  1067.         fprintf(file, "\tif (msgh_size != %d + msgh_size_delta)\n",
  1068.         rt->rtReplySize);
  1069.     else
  1070.         fprintf(file, "\tif (msgh_size < %d + msgh_size_delta)\n",
  1071.         rt->rtReplySize);
  1072.     WriteMsgError(file, rt, "MIG_TYPE_ERROR");
  1073.  
  1074.     if (!LastVarArg)
  1075.         fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
  1076.  
  1077.     fprintf(file, "#endif\tTypeCheck\n");
  1078.     }
  1079.     fprintf(file, "\n");
  1080. }
  1081.  
  1082. /*************************************************************
  1083.  *  Write code to copy an argument from the reply message
  1084.  *  to the parameter. Called by WriteRoutine for each argument
  1085.  *  in the reply message.
  1086.  *************************************************************/
  1087. static void
  1088. WriteExtractArgValue(file, arg)
  1089.     FILE *file;
  1090.     register argument_t *arg;
  1091. {
  1092.     register ipc_type_t    *argType = arg->argType;
  1093.     register char *ref = argByReferenceUser(arg) ? "*" : "";
  1094.  
  1095.     if (argType->itInLine && argType->itVarArray) {
  1096.  
  1097.     if (argType->itString) {
  1098.         /*
  1099.          *    Copy out variable-size C string with mig_strncpy.
  1100.          */
  1101.         fprintf(file, "\t(void) mig_strncpy(%s%s, OutP->%s, %d);\n",
  1102.         ref,
  1103.         arg->argVarName,
  1104.         arg->argMsgField,
  1105.         argType->itNumber * argType->itTypeSize);
  1106.     }
  1107.     else {
  1108.  
  1109.         /*
  1110.          *    Copy out variable-size inline array with bcopy,
  1111.          *    after checking that number of elements doesn`t
  1112.          *    exceed user`s maximum.
  1113.          */
  1114.         register argument_t *count = arg->argCount;
  1115.         register char *countRef = argByReferenceUser(count) ? "*" : "";
  1116.         register ipc_type_t *btype = argType->itElement;
  1117.  
  1118.         /* Note count->argMultiplier == btype->itNumber */
  1119.  
  1120.         fprintf(file, "\tif (OutP->%s", count->argMsgField);
  1121.         if (btype->itNumber > 1)
  1122.         fprintf(file, " / %d", btype->itNumber);
  1123.         fprintf(file, " > %s%s) {\n",
  1124.         countRef, count->argVarName);
  1125.  
  1126.         if (argType->itIndefinite) {
  1127.         /*
  1128.          * If number of elements is too many for user receiving area,
  1129.          * put a pointer to the data in the start of the user receiving
  1130.          * area.  If the data is in-line, allocate memory and copy the
  1131.          * data to it.
  1132.          */
  1133.         fprintf(file, "\t\tif (OutP->%s.msgtl_header.msgt_inline) {\n",
  1134.             arg->argMsgField);
  1135.         fprintf(file, "\t\t\t(void) vm_allocate(mach_task_self(),\n");
  1136.         fprintf(file, "\t\t\t\t(vm_offset_t *)%s%s,\n\t\t\t\t",
  1137.             ref, arg->argVarName);
  1138.         if (btype->itTypeSize != btype->itNumber)
  1139.             fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber);
  1140.         fprintf(file, "OutP->%s, TRUE);\n",
  1141.             count->argMsgField);
  1142.         fprintf(file, "\t\t\tbcopy(*(char **)OutP->%s,*(char **)%s%s, ",
  1143.             arg->argMsgField, ref, arg->argVarName);
  1144.         if (btype->itTypeSize != btype->itNumber)
  1145.             fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber);
  1146.         fprintf(file, "OutP->%s);\n", count->argMsgField);
  1147.         fprintf(file, "\t\t} else {\n");
  1148.         fprintf(file, "\t\t\t*((%s **)%s%s) = *((%s **)OutP->%s);\n",
  1149.             FetchUserType(btype), ref, arg->argVarName,
  1150.             FetchUserType(btype), arg->argMsgField);
  1151.         fprintf(file, "\t\t}\n");
  1152.         }
  1153.         else {
  1154.         /*
  1155.          * If number of elements is too many for user receiving area,
  1156.          * fill user`s area as much as possible.  Return the correct
  1157.          * number of elements.
  1158.          */
  1159.         fprintf(file, "\t\tbcopy((char *) OutP->%s, (char *) %s%s, ",
  1160.             arg->argMsgField, ref, arg->argVarName);
  1161.         if (btype->itTypeSize > 1)
  1162.             fprintf(file, "%d * ", btype->itTypeSize);
  1163.         fprintf(file, "%s%s);\n",
  1164.             countRef, count->argVarName);
  1165.  
  1166.         fprintf(file, "\t\t%s%s = OutP->%s",
  1167.               countRef, count->argVarName, count->argMsgField);
  1168.         if (btype->itNumber > 1)
  1169.             fprintf(file, " / %d", btype->itNumber);
  1170.         fprintf(file, ";\n");
  1171.         WriteMsgError(file,arg->argRoutine, "MIG_ARRAY_TOO_LARGE");
  1172.         }
  1173.         fprintf(file, "\t}\n\telse {\n");
  1174.  
  1175.         fprintf(file, "\t\tbcopy((char *) OutP->%s, (char *) %s%s, ",
  1176.         arg->argMsgField, ref, arg->argVarName);
  1177.         if (btype->itTypeSize != btype->itNumber)
  1178.         fprintf(file, "%d * ",
  1179.             btype->itTypeSize/btype->itNumber);
  1180.         fprintf(file, "OutP->%s);\n",
  1181.         count->argMsgField);
  1182.         fprintf(file, "\t}\n");
  1183.     }
  1184.     }
  1185.     else if (arg->argMultiplier > 1)
  1186.     WriteCopyType(file, argType,
  1187.               "%s%s", "/* %s%s */ OutP->%s / %d",
  1188.               ref, arg->argVarName, arg->argMsgField,
  1189.               arg->argMultiplier);
  1190.     else
  1191.     WriteCopyType(file, argType,
  1192.               "%s%s", "/* %s%s */ OutP->%s",
  1193.               ref, arg->argVarName, arg->argMsgField);
  1194.     fprintf(file, "\n");
  1195. }
  1196.  
  1197. static void
  1198. WriteExtractArg(file, arg)
  1199.     FILE *file;
  1200.     register argument_t *arg;
  1201. {
  1202.     register routine_t *rt = arg->argRoutine;
  1203.  
  1204.     if (akCheck(arg->argKind, akbReply))
  1205.     WriteTypeCheck(file, arg);
  1206.  
  1207.     if (akCheckAll(arg->argKind, akbVariable|akbReply))
  1208.     WriteCheckMsgSize(file, arg);
  1209.  
  1210.     /* Now that the RetCode is type-checked, check its value.
  1211.        Must abort immediately if it isn't KERN_SUCCESS, because
  1212.        in that case the reply message is truncated. */
  1213.  
  1214.     if (arg == rt->rtRetCode)
  1215.     WriteRetCodeCheck(file, rt);
  1216.  
  1217.     if (akCheckAll(arg->argKind, akbReturnRcv))
  1218.     WriteExtractArgValue(file, arg);
  1219. }
  1220.  
  1221. WriteAdjustReplyMsgPtr(file, arg)
  1222.     FILE *file;
  1223.     register argument_t *arg;
  1224. {
  1225.     register ipc_type_t *ptype = arg->argType;
  1226.  
  1227.     fprintf(file,
  1228.     "\tOutP = (Reply *) ((char *) OutP + msgh_size_delta - %d);\n\n",
  1229.     ptype->itTypeSize + ptype->itPadSize);
  1230. }
  1231.  
  1232. void
  1233. WriteReplyArgs(file, rt)
  1234.     FILE *file;
  1235.     register routine_t *rt;
  1236. {
  1237.     register argument_t *arg;
  1238.     register argument_t *lastVarArg;
  1239.  
  1240.     lastVarArg = argNULL;
  1241.     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
  1242.  
  1243.     /*
  1244.      * Advance message pointer if the last reply argument was
  1245.      * variable-length and the reply position will change.
  1246.      */
  1247.     if (lastVarArg != argNULL &&
  1248.         lastVarArg->argReplyPos < arg->argReplyPos)
  1249.     {
  1250.         WriteAdjustReplyMsgPtr(file, lastVarArg);
  1251.         lastVarArg = argNULL;
  1252.     }
  1253.  
  1254.     /*
  1255.      * Copy the argument
  1256.      */
  1257.     WriteExtractArg(file, arg);
  1258.  
  1259.     /*
  1260.      * Remember whether this was variable-length.
  1261.      */
  1262.     if (akCheckAll(arg->argKind, akbReturnRcv|akbVariable))
  1263.         lastVarArg = arg;
  1264.     }
  1265. }
  1266.  
  1267. /*************************************************************
  1268.  *  Writes code to return the return value. Called by WriteRoutine
  1269.  *  for routines and functions.
  1270.  *************************************************************/
  1271. static void
  1272. WriteReturnValue(file, rt)
  1273.     FILE *file;
  1274.     routine_t *rt;
  1275. {
  1276.     if (rt->rtReturn == rt->rtRetCode)
  1277.     /* If returning RetCode, we have already checked that it is
  1278.        KERN_SUCCESS */
  1279.     fprintf(file, "\treturn KERN_SUCCESS;\n");
  1280.  
  1281.     else
  1282.     {
  1283.     if (rt->rtNumReplyVar > 0)
  1284.         fprintf(file, "\tOutP = &Mess.Out;\n");
  1285.  
  1286.     fprintf(file, "\treturn OutP->%s;\n", rt->rtReturn->argMsgField);
  1287.     }
  1288. }
  1289.  
  1290. /*************************************************************
  1291.  *  Writes the elements of the message type declaration: the
  1292.  *  msg_type structure, the argument itself and any padding 
  1293.  *  that is required to make the argument a multiple of 4 bytes.
  1294.  *  Called by WriteRoutine for all the arguments in the request
  1295.  *  message first and then the reply message.
  1296.  *************************************************************/
  1297. static void
  1298. WriteFieldDecl(file, arg)
  1299.     FILE *file;
  1300.     argument_t *arg;
  1301. {
  1302.     WriteFieldDeclPrim(file, arg, FetchUserType);
  1303. }
  1304.  
  1305. static void
  1306. WriteStubDecl(file, rt)
  1307.     FILE *file;
  1308.     register routine_t *rt;
  1309. {
  1310.     fprintf(file, "\n");
  1311.     fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
  1312.     fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName);
  1313.     fprintf(file, "#if\t%s\n", NewCDecl);
  1314.     fprintf(file, "(\n");
  1315.     WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
  1316.     fprintf(file, ")\n");
  1317.     fprintf(file, "#else\n");
  1318.     fprintf(file, "\t(");
  1319.     WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
  1320.     fprintf(file, ")\n");
  1321.     WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
  1322.     fprintf(file, "#endif\n");
  1323.     fprintf(file, "{\n");
  1324. }
  1325.  
  1326. /*************************************************************
  1327.  *  Writes all the code comprising a routine body. Called by
  1328.  *  WriteUser for each routine.
  1329.  *************************************************************/
  1330. static void
  1331. WriteRoutine(file, rt)
  1332.     FILE *file;
  1333.     register routine_t *rt;
  1334. {
  1335.     /* write the stub's declaration */
  1336.  
  1337.     WriteStubDecl(file, rt);
  1338.  
  1339.     /* typedef of structure for Request and Reply messages */
  1340.  
  1341.     WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request");
  1342.     if (!rt->rtOneWay)
  1343.     WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply");
  1344.  
  1345.     /* declarations for local vars: Union of Request and Reply messages,
  1346.        InP, OutP and return value */
  1347.  
  1348.     WriteVarDecls(file, rt);
  1349.  
  1350.     /* declarations and initializations of the mach_msg_type_t variables
  1351.        for each argument */
  1352.  
  1353.     WriteList(file, rt->rtArgs, WriteTypeDeclIn, akbRequest, "\n", "\n");
  1354.     if (!rt->rtOneWay)
  1355.     WriteList(file, rt->rtArgs, WriteCheckDecl, akbReplyQC, "\n", "\n");
  1356.  
  1357.     /* fill in all the request message types and then arguments */
  1358.  
  1359.     WriteRequestArgs(file, rt);
  1360.  
  1361.     /* fill in request message head */
  1362.  
  1363.     WriteRequestHead(file, rt);
  1364.     fprintf(file, "\n");
  1365.  
  1366.     /* Write the send/receive or rpc call */
  1367.  
  1368.     if (rt->rtOneWay)
  1369.     WriteMsgSend(file, rt);
  1370.     else
  1371.     {
  1372.     if (UseMsgRPC)
  1373.         WriteMsgRPC(file, rt);
  1374.     else
  1375.         WriteMsgSendReceive(file, rt);
  1376.  
  1377.     /* Check the values that are returned in the reply message */
  1378.  
  1379.     WriteCheckIdentity(file, rt);
  1380.  
  1381.     /* If the reply message has no Out parameters or return values
  1382.        other than the return code, we can type-check it and
  1383.        return it directly. */
  1384.  
  1385.     if (rt->rtNoReplyArgs)
  1386.     {
  1387.         WriteTypeCheck(file, rt->rtRetCode);
  1388.  
  1389.         fprintf(file, "\treturn OutP->RetCode;\n");
  1390.     }
  1391.     else {
  1392.         WriteReplyArgs(file, rt);
  1393.  
  1394.         /* return the return value, if any */
  1395.  
  1396.         if (rt->rtProcedure)
  1397.         fprintf(file, "\t/* Procedure - no return needed */\n");
  1398.         else
  1399.         WriteReturnValue(file, rt);
  1400.     }
  1401.     }
  1402.  
  1403.     fprintf(file, "}\n");
  1404. }
  1405.  
  1406. /*************************************************************
  1407.  *  Writes out the xxxUser.c file. Called by mig.c
  1408.  *************************************************************/
  1409. void
  1410. WriteUser(file, stats)
  1411.     FILE *file;
  1412.     statement_t *stats;
  1413. {
  1414.     register statement_t *stat;
  1415.  
  1416.     WriteProlog(file);
  1417.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  1418.     switch (stat->stKind)
  1419.     {
  1420.       case skRoutine:
  1421.         WriteRoutine(file, stat->stRoutine);
  1422.         break;
  1423.       case skImport:
  1424.       case skUImport:
  1425.       case skSImport:
  1426.         break;
  1427.       default:
  1428.         fatal("WriteUser(): bad statement_kind_t (%d)",
  1429.           (int) stat->stKind);
  1430.     }
  1431.     WriteEpilog(file);
  1432. }
  1433.  
  1434. /*************************************************************
  1435.  *  Writes out individual .c user files for each routine.  Called by mig.c
  1436.  *************************************************************/
  1437. void
  1438. WriteUserIndividual(stats)
  1439.     statement_t *stats;
  1440. {
  1441.     register statement_t *stat;
  1442.  
  1443.     for (stat = stats; stat != stNULL; stat = stat->stNext)
  1444.     switch (stat->stKind)
  1445.     {
  1446.       case skRoutine:
  1447.         {
  1448.         FILE *file;
  1449.         register char *filename;
  1450.  
  1451.         filename = strconcat(UserFilePrefix,
  1452.                      strconcat(stat->stRoutine->rtName, ".c"));
  1453.         file = fopen(filename, "w");
  1454.         if (file == NULL)
  1455.             fatal("fopen(%s): %s", filename,
  1456.               unix_error_string(errno));
  1457.         WriteProlog(file);
  1458.         WriteRoutine(file, stat->stRoutine);
  1459.         WriteEpilog(file);
  1460.         fclose(file);
  1461.         strfree(filename);
  1462.         }
  1463.         break;
  1464.       case skImport:
  1465.       case skUImport:
  1466.       case skSImport:
  1467.         break;
  1468.       default:
  1469.         fatal("WriteUserIndividual(): bad statement_kind_t (%d)",
  1470.           (int) stat->stKind);
  1471.     }
  1472. }
  1473.